# coding: utf8

import pandas as pd
import numpy as np


class Demo:

    def __init__(self):
        self.df_list = pd.DataFrame(
            data=[[(x + 1) ** y for y in range(3)] for x in range(3)],
            columns=list('ABC'),
            index=pd.date_range('2010.1.1', periods=3),
            dtype=np.int8)
        self.df_mindex2 = pd.DataFrame(np.arange(60, 84).reshape(12, 2),
                           columns=['math', 'science'],
                           index=pd.MultiIndex.from_product(
                               [[1, 2, 3], ['t1', 't2', 't3', 't4']]),
                           dtype=np.uint8)
        return

    def sel_use_index(self):
        df1 = self.df_list
        df2 = self.df_mindex2
        sr = pd.Series(data=range(6), index=pd.MultiIndex.from_product([[0, 1], list('abc')]))
        sr1 = pd.Series([1, 3, 5], index=range(1, 4))

        print(
            f"{'='*80}\n"
            f" >>> df1\n"
            f"{df1}\n"
            f" >>> sr\n"
            f"{sr}\n"
            f" >>> sr1\n"
            f"{sr1}\n"
            f"# --- 下标方式 ---\n"
            f"# Series中使用索引切片\n"
            f" >>> sr[(0, 'b'):(1, 'b')]\n"
            f"{sr[(0, 'b'):(1, 'b')]}\n"
            f"# Series中使用单个索引标签\n"
            f" >>> sr[(0, 'c')]\n"
            f"{sr[(0, 'c')]}\n"
            f"# 当标签和行索引号冲突时，优先使用行号\n"
            f" >>> sr1[2]\n"
            f"{sr1[2]}\n"
            f" >>> sr1[1:3]\n"
            f"{sr1[1:3]}\n"
            
            f"# 单层索引中使用标签切片\n"
            f" >>> df\n"
            f"{df1}\n"
            f" >>> \n"
            f"{df1[pd.Timestamp(2010, 1, 1):pd.Timestamp(2010, 1, 2)]}\n"

            f"{'-' * 80}\n"
            f"# 多层索引中使用标签切片\n"
            f" >>> \n"
            f"{df2[(1, 't2'):(2, 't1')]}\n"

            f"{'=' * 80}\n"
            f"# --- loc方式 ---\n"
            f""

            f"{'=' * 80}\n"
            f"# --- iloc方式 ---\n"
            f" 不能使用！\n"

            f"{'=' * 80}\n"
            f"# --- at方式 ---\n"
            f" >>> df1.at[pd.Timestamp(2010, 1, 1), 'A']\n"
            f"{df1.at[pd.Timestamp(2010, 1, 1), 'A']}\n"
            f" >>> df2.at[(1, 't2'), 'science']\n"
            f"{df2.at[(1, 't2'), 'science']}\n"

            f"{'=' * 80}\n"
            f"# --- iat方式 ---\n"
            f" 不能使用！\n"
        )
        return

    def sel_use_bool_seq(self):
        df1 = self.df_list
        df2 = self.df_mindex2.unstack()

        print(
            f"{'='*80}\n"
            f"# --- 下标方式 ---\n"
            f"{'-' * 80}\n"
            f"# 单层索引中使用标签切片\n"
            f" >>> df1\n"
            f"{df1}\n"
            
            f"{df1[[True, False, True]]}\n"
            f""
            f" >>> df2\n"
            f"{df2}\n"
            f" >>> df2.loc[[True, 3], :]\n"
            f"{df2.loc[[True, 3, 3], :]}\n"
        )

    def sel_use_pos(self):
        sr = pd.Series(data=range(6), index=pd.MultiIndex.from_product([[0, 1], list('abc')]))
        sr = sr.drop((0, 'c'))
        # print(sr)

        df = self.df_mindex2.unstack()
        # df2 = self.df_list

        print(
            f"{'='*80}\n"
            f" >>> df1\n"
            f"{df}\n"
            
            f"{'=' * 80}\n"
            f"# --- 下标方式 ---\n"
            f"# 使用单个行号进行选取\n"
            f" >>> sr[1]\n"
            f"{sr[1]}\n"
            f" >>> df1[1]\n"
            f" Traceback (most recent call last):\n"
            f"   ...\n"
            f"   raise KeyError(key) from err\n"
            "  KeyError: 1\n"
            f"# 下标方式仅支持位置切片，即行号切片\n"
            f" >>> sr[0:2]\n"
            f"{sr[0:2]}"
            f" >>> df1[1:3]\n"
            f"{df[0:2]}\n"
        )
        # return

        print(
            f"{'=' * 80}\n"
            f"# --- iloc方式 ---\n"
            f"# 使用单个位置，选取单行数据，返回Series\n"
            f" >>> df1.iloc[0]\n"
            f"{df.iloc[0]}\n"
            
            f"{'-' * 80}\n"
            f"# 使用两个位置，选取对应行列号的单个数据值，返回标量值\n"
            f" >>> df1.iloc[0, 1]\n"
            f"{df.iloc[0, 1]}\n"

            f"{'-' * 80}\n"
            f"使用单个位置序列，选取多个行数据，返回DataFrame\n"
            f" >>> df1.iloc[[0, 1]]\n"
            f"{df.iloc[[0, 1]]}\n"

            f"{'-' * 80}\n"
            f"# 使用两个位置序列，选取多行、多列数据，返回DataFrame\n"
            f" >>> df1.iloc[[0, 1], [3, 4, 5]]\n"
            f"{df.iloc[[0, 1], [3, 4, 5]]}\n"

            f"{'-' * 80}\n"
            f"# 使用单个切片，选取多行行数据，返回DataFrame\n"
            f" >>> df1.iloc[0:1]\n"
            f"{df.iloc[0:1]}\n"
            
            f"{'-' * 80}\n"
            f"# 使用行切片、列切片，选取多行多列数据，返回DataFrame\n"
            f" >>> df1.iloc[0:1, 3:5]\n"
            f"{df.iloc[0:1, 3:5]}\n"
            
            f"{'-' * 80}\n"
            f"# 使用混合定位方式：单个行号、列切片， 返回Series\n"
            f" >>> df1.iloc[1, 3:5]\n"
            f"{df.iloc[1, 3:5]}\n"

            f"{'=' * 80}\n"
            f"# --- iat方式 ---\n"
            f"# iat使用单个行、列号进行定位，选取单个数值， 返回标量值\n"
            f" >>> df1.iat[0, 3]\n"
            f"{df.iat[0, 3]}\n"
            f"{'=' * 80}\n"
        )

        # 混合定位
        print(
            f"{'-' * 80}\n"
            f"# 使用混合定位方式：行切片、单个列号， 返回Series\n"
            f" >>> df1.iloc[0:1, 3]\n"
            f"{df.iloc[0:1, 3]}\n"
        )
        return df

    # old version

    def data_loc_at(self):
        df = self.df_mindex2
        df = df.unstack()
        df.sort_index(axis=1)
        df2 = self.df_list
        df3 = self.df_mindex2

        print(
            f' >>> df\n {df}\n'
            "--- six mode to select data ---\n"
            f'{"="*80}\n'
            " ---《下标方式[]选取》\n"
            f'{"=-"*40}\n'
            " # 行号切片：\n"
            " >>> df[0:1]\n"
            f"{df[0:2]}\n"
            f"{'-'*80}\n"

            "---行标签切片\n"
            "行标签切片， 单层时间序列\n"
            " >>> df2\n"
            f"{df2}\n"
            " >>> df2[df2.index[0]:df2.index[1]]\n"
            f"{df2[df2.index[0]:df2.index[1]]}\n"

            "行标签切片， 多层索引\n"
            " >>> df\n"
            f"{df3}\n"
            " >>> df[(1, 't1'):(2, 't3')]\n"
            f"{df3[(1, 't1'):(2, 't3')]}\n"

            f'{"-"*80}\n'
            " # 列标签：\n"
            " >>> df[('math', 't2')]\n"
            f"{df[('math', 't2')]}\n"
            f'{"-"*80}\n'
            " # 列标签序列：\n"
            " >>> df[[('math', 't2'), ('science', 't3')]]\n"
            f"{df[[('math', 't2'), ('science', 't3')]]}\n"

            f"{'='*80}\n"
            "《.iat选取》\n"
            f"{'-'*80}\n"
            " # 使用位置，选取单个数据：\n"
            " >>> df.iat[1, 2]\n"
            f"{df.iat[1, 2]}\n"

            f'{"="*80}\n'
            "《.iloc选取》\n"
            " # 使用位置，选取单个数据：\n"
            " >>> df.iloc[1, 2]\n"
            f'{df.iloc[1, 2]}'
      
            f'{"-"*80}\n'
            " # 行列号切片，选取单个数据：\n"
            " >>> df.iloc[1:3, 3:5]\n"
            f"{df.iloc[1:3, 3:5]}\n"

            f'{"-"*80}\n'
            "行列号序列，选取多个数据：\n"
            " >>> df.iloc[[1, 2], [3, 7]]\n"
            f"{df.iloc[[1, 2], [3, 7]]}\n"
        
            f'{"="*80}\n'
            "《.at选取》\n"
            " # 使用标签，选取单个数据：\n"
            " >>> df.at[1, ('math', 't2')]\n"
            f"{df.at[1, ('math', 't2')]}\n"
        
            f'{"="*80}\n'
            "《.loc使用标签选取多个数据》\n"
            f'{"-"*80}\n'
            " # 单标签选取\n"
            " >>> df.loc[1, ('math', 't2')]\n"
            f"{df.loc[1, ('math', 't2')]}\n"
        
            f'{"-."*40}\n'
            " # 标签切片：\n"
            " >>> df.loc[1:3, ('math', 't2'):('science', 't3')]\n"
            f"{df.loc[1:3, ('math', 't2'):('science', 't3')]}\n"
        
            f'{"-."*40}\n'
            " # 标签序列：\n"
            " >>> df.loc[[1, 3], [('math', 't2'), ('science', 't1')]]\n"
            f"{df.loc[[1, 3], [('math', 't2'), ('science', 't1')]]}\n"
        
            f'{"="*80}\n'
            "《布尔序列选取》\n"
        
            f'{"-"*80}\n'
            "下标[]中使用布尔序列选取\n"
        
            f'{"-."*40}\n'
            " # 下标[]中使用布尔序列选取行：\n"
            " >>> df[[True, False, False]]\n"
            f"{df[[True, False, False]]}\n"
        
            f'{"-"*80}\n'
            " # 下标[]中使用列数据产生的逻辑表达式选取行：\n"
            " >>> df[df[('math', 't1')]<70]\n"
            f"{df[df[('math', 't1')] < 70]}\n"
        
            f'{"-"*80}\n'
            ".loc中使用布尔序列选取\n"
        
            f'{"="*80}\n'
            " # 行布尔序列：\n"
            " >>> df.loc[[True, True, False]]\n"
            f"{df.loc[[True, True, False]]}\n"
        
            f'{"-"*80}\n'
            " # 列布尔序列："
            " >>> df.loc[:, [True]*3 + [False]*5]\n"
            f"{df.loc[:, [True]*3 + [False]*5]}\n"
        
            f'{"-"*80}\n'
            " # 列布尔序列: 使用逻辑表达式产生列布尔序列 \n"
            " >>> df.loc[:, df.loc[1,:]>65]\n"
            f"{df.loc[:, df.loc[1,:]>65]}\n"
        
            f'{"-"*80}\n'
            " # 行切片与列布尔序列混合使用：\n"
            " # （标签切片包含两端数据）\n"
            " >>> df.loc[2:3, df.loc[1,:]>66]\n"
            f"{df.loc[2:3, df.loc[1, :] > 66]}\n"
        
            f'{"="*80}')

        return

    def df_view(self):
        df = self.df5
        df = df.unstack()
        df.sort_index(axis=1)

        print('df')
        print(df)

        print("--- six mode to select data ---")
        print("="*80)
        print("\n下标方式[]选取")
        print("=-"*40)

        print("行号切片：df[0:1]")
        print(df[0:2])

        print("-"*80)
        print("行标签切片")

        print("时间序列标签切片")
        df2 = self.df1
        print(df2)
        print("df2[df2.index[0]:df2.index[1]]")
        print(df2[df2.index[0]:df2.index[1]])

        print("多重索引标签切片")
        df2 = self.df5
        print(df2)
        print("df2[(1, 't1'):(2, 't3')]")
        print(df2[(1, 't1'):(2, 't3')])
        # print(df2[df2.index[0]:df2.index[2]])

        print("-"*80)
        print("列标签：df[('math', 't2')]")
        print(df[('math', 't2')])

        print("-"*80)
        print("列标签序列：df[[('math', 't2'), ('science', 't3')]]")
        print(df[[('math', 't2'), ('science', 't3')]])

        print("="*80)
        print("\n .iat选取")
        print("选取单个数据：df.iat[1, 2]")
        print(df.iat[1, 2])

        print("="*80)
        print("\n .iloc选取")
        print("=-"*40)
        print("按行列号坐标，选取单个数据：df.iloc[1, 2]")
        print(df.iloc[1, 2])

        print("-"*80)
        print("按行列号切片，选取单个数据：df.iloc[1:3, 3:5]")
        print(df.iloc[1:3, 3:5])

        print("-"*80)
        print("按行列号序列，选取多个数据：df.iloc[[1, 2], [3, 7]]")
        print(df.iloc[[1, 2], [3, 7]])
        print("=-"*40)

        print("="*80)
        print("\n .at选取")
        print("使用标签选取单个数据：df.at[1, ('math', 't2')]")
        print(df.at[1, ('math', 't2')])

        print("="*80)
        print("\n .loc使用标签选取多个数据")
        print("单标签：df.loc[1, ('math', 't2')]")
        print(df.loc[1, ('math', 't2')])
        print("标签切片：df.loc[1:3, ('math', 't2'):('science', 't3')]")
        print(df.loc[1:3, ('math', 't2'):('science', 't3')])
        print("标签序列：df.loc[[1, 3], [('math', 't2'), ('science', 't1')]]")
        print(df.loc[[1, 3], [('math', 't2'), ('science', 't1')]])

        print("="*80)
        print("布尔序列选取")

        print("-"*80)
        print("下标中[]使用布尔序列选取行：df[[True, False, False]]")
        print(df[[True, False, False]])

        print("-"*80)
        print("列逻辑表达式（行布尔Series序列）：df[('math', 't1')] < 70")
        print(df[df[('math', 't1')] < 70])

        print("=-"*40)
        print(".loc中使用布尔序列选取")

        print("-"*80)
        print("使用行布尔序列：df.loc[[True, True, False]]")
        print(df.loc[[True, True, False]])

        print("-"*80)
        print("使用列布尔序列：df.loc[:, [True]*3 + [False]*5")
        print(df.loc[:, [True]*3 + [False]*5])

        print("-"*80)
        print("使用逻辑表达式产生列布尔序列：df.loc[:, df.loc[1,:]>65]")
        print(df.loc[:, df.loc[1,:]>65])

        print("-"*80)
        print("切片与布尔序列混合使用（标签切片包含两端）：df.loc[2:3, df.loc[1,:]>65]")
        print(df.loc[2:3, df.loc[1,:]>65])

    # some methods should not belong to data look

    def data_head_tail(self):
        """
        """
        df = self.df_list

        print(" >>> df\n"
              f"{df}"
              " >>> df.head(2)\n"
              f"{df.head(2)}\n"
              " >>> df.tail(2)\n"
              f" {df.tail(2)}")
        return

    def data_sample(self):
        """
        sample(self: ~FrameOrSeries, n=None, frac=None, replace=False, weights=None, random_state=None, axis=None)
              -> ~FrameOrSeries

            Return a random sample of items from an axis of object.

            You can use `random_state` for reproducibility.

            Parameters
            ----------
            n : int, optional
                Number of items from axis to return. Cannot be used with `frac`.
                Default = 1 if `frac` = None.
            frac : float, optional
                Fraction of axis items to return. Cannot be used with `n`.
            replace : bool, default False
                Allow or disallow sampling of the same row more than once.
            weights : str or ndarray-like, optional
                Default 'None' results in equal probability weighting.
                If passed a Series, will align with target object on index. Index
                values in weights not found in sampled object will be ignored and
                index values in sampled object not in weights will be assigned
                weights of zero.
                If called on a DataFrame, will accept the name of a column
                when axis = 0.
                Unless weights are a Series, weights must be same length as axis
                being sampled.
                If weights do not sum to 1, they will be normalized to sum to 1.
                Missing values in the weights column will be treated as zero.
                Infinite values not allowed.
            random_state : int, array-like, BitGenerator, np.random.RandomState, optional
                If int, array-like, or BitGenerator (NumPy>=1.17), seed for
                random number generator
                If np.random.RandomState, use as numpy RandomState object.

                .. versionchanged:: 1.1.0

                    array-like and BitGenerator (for NumPy>=1.17) object now passed to
                    np.random.RandomState() as seed
            axis : {0 or ‘index’, 1 or ‘columns’, None}, default None
                Axis to sample. Accepts axis number or name. Default is stat axis
                for given data type (0 for Series and DataFrames).

            Returns
            -------
            Series or DataFrame
                A new object of same type as caller containing `n` items randomly
                sampled from the caller object.

            See Also
            --------
            DataFrameGroupBy.sample: Generates random samples from each group of a
                DataFrame object.
            SeriesGroupBy.sample: Generates random samples from each group of a
                Series object.
            numpy.random.choice: Generates a random sample from a given 1-D numpy
                array.

            Notes
            -----
            If `frac` > 1, `replacement` should be set to `True`.

            Examples
            --------
            >>> df = pd.DataFrame({'num_legs': [2, 4, 8, 0],
            ...                    'num_wings': [2, 0, 0, 0],
            ...                    'num_specimen_seen': [10, 2, 1, 8]},
            ...                   index=['falcon', 'dog', 'spider', 'fish'])
            >>> df
                    num_legs  num_wings  num_specimen_seen
            falcon         2          2                 10
            dog            4          0                  2
            spider         8          0                  1
            fish           0          0                  8

            Extract 3 random elements from the ``Series`` ``df['num_legs']``:
            Note that we use `random_state` to ensure the reproducibility of
            the examples.

            >>> df['num_legs'].sample(n=3, random_state=1)
            fish      0
            spider    8
            falcon    2
            Name: num_legs, dtype: int64

            A random 50% sample of the ``DataFrame`` with replacement:

            >>> df.sample(frac=0.5, replace=True, random_state=1)
                  num_legs  num_wings  num_specimen_seen
            dog          4          0                  2
            fish         0          0                  8

            An upsample sample of the ``DataFrame`` with replacement:
            Note that `replace` parameter has to be `True` for `frac` parameter > 1.

            >>> df.sample(frac=2, replace=True, random_state=1)
                    num_legs  num_wings  num_specimen_seen
            dog            4          0                  2
            fish           0          0                  8
            falcon         2          2                 10
            falcon         2          2                 10
            fish           0          0                  8
            dog            4          0                  2

            Using a DataFrame column as weights. Rows with larger value in the
            `num_specimen_seen` column are more likely to be sampled.

            >>> df.sample(n=2, weights='num_specimen_seen', random_state=1)
                    num_legs  num_wings  num_specimen_seen
            falcon         2          2                 10
            fish           0          0                  8
        """
        data = np.random.randint(0, 10, (10, 3))
        df = pd.DataFrame(data=data, columns=list('ABC'))
        for j in range(len(data)):
            df.iloc[j] += j*100
        print(
            " >>> df\n"
            f"{df}\n"
            " # 缺省情况下axis=0，随机抽取数据行，设置n=3抽取3行数据\n"
            " >>> df.sample(3)\n"
            f"{df.sample(3)}\n"

            f" # 设置axis=1，沿列向抽取，设置n=2，随机抽取2列数据\n"
            " >>> df.sample(2, axis=1)\n"
            f"{df.sample(2, axis=1)}\n"

            f" # 设置frac按比例随机抽取数据行, 同时设置random_stat保证多次抽样相同\n"
            " >>> df.sample(frac=0.2, random_stat=1)\n"
            f"{df.sample(frac=0.2, random_state=1)}\n"
            " >>> df.sample(frac=0.2, random_stat=1)\n"
            f"{df.sample(frac=0.2, random_state=1)}\n"

            f" # 设置weight为列名，按该列的值为权重，随机抽取数据行\n"
            " >>> df.sample(frac=1.2, weight='B', replace=True)\n"
            f"{df.sample(frac=1.2, weights='B', replace=True)}\n"

            f" # 设置weight为数组，按该数组值为权重，设置axis=1和n=2，随机抽取2列数据\n"
            " >>> df.sample(n=2, weight=[1, 3, 5], axis=1)\n"
            f"{df.sample(n=2, weights=[1, 3, 7], axis=1, random_state=2)}\n"
        )
        return

    def data_xs(self):
        """
        xs(self, key, axis=0, level=None, drop_level: 'bool_t' = True)

            Return cross-section from the Series/DataFrame.

            This method takes a `key` argument to select data at a particular
            level of a MultiIndex.

            Parameters
            ----------
            key : label or tuple of label
                Label contained in the index, or partially in a MultiIndex.
            axis : {0 or 'index', 1 or 'columns'}, default 0
                Axis to retrieve cross-section on.
            level : object, defaults to first n levels (n=1 or len(key))
                In case of a key partially contained in a MultiIndex, indicate
                which levels are used. Levels can be referred by label or position.
            drop_level : bool, default True
                If False, returns object with same levels as self.

            Returns
            -------
            Series or DataFrame
                Cross-section from the original Series or DataFrame
                corresponding to the selected index levels.

            See Also
            --------
            DataFrame.loc : Access a group of rows and columns
                by label(s) or a boolean array.
            DataFrame.iloc : Purely integer-location based indexing
                for selection by position.

            Notes
            -----
            `xs` can not be used to set values.

            MultiIndex Slicers is a generic way to get/set values on
            any level or levels.
            It is a superset of `xs` functionality, see
            :obj:`MultiIndex Slicers <advanced.mi_slicers>`.

            Examples
            --------
            >>> d = {'num_legs': [4, 4, 2, 2],
            ...      'num_wings': [0, 0, 2, 2],
            ...      'class': ['mammal', 'mammal', 'mammal', 'bird'],
            ...      'animal': ['cat', 'dog', 'bat', 'penguin'],
            ...      'locomotion': ['walks', 'walks', 'flies', 'walks']}
            >>> df = pd.DataFrame(data=d)
            >>> df = df.set_index(['class', 'animal', 'locomotion'])
            >>> df
                                       num_legs  num_wings
            class  animal  locomotion
            mammal cat     walks              4          0
                   dog     walks              4          0
                   bat     flies              2          2
            bird   penguin walks              2          2

            Get values at specified index

            >>> df.xs('mammal')
                               num_legs  num_wings
            animal locomotion
            cat    walks              4          0
            dog    walks              4          0
            bat    flies              2          2

            Get values at several indexes

            >>> df.xs(('mammal', 'dog'))
                        num_legs  num_wings
            locomotion
            walks              4          0

            Get values at specified index and level

            >>> df.xs('cat', level=1)
                               num_legs  num_wings
            class  locomotion
            mammal walks              4          0

            Get values at several indexes and levels

            >>> df.xs(('bird', 'walks'),
            ...       level=[0, 'locomotion'])
                     num_legs  num_wings
            animal
            penguin         2          2

            Get values at specified column and axis

            >>> df.xs(('bird', 'walks'),
            ...       level=[0, 'locomotion'])
                     num_legs  num_wings
            animal
            penguin         2          2

            Get values at specified column and axis

            >>> df.xs('num_wings', axis=1)
            class   animal   locomotion
            mammal  cat      walks         0
                    dog      walks         0
                    bat      flies         2
            bird    penguin  walks         2
            Name: num_wings, dtype: int64
        """
        from ch4data import sec0_datasets as dds
        df = dds.DataSet.df5
        df = df.stack()
        df1 = df.unstack().unstack()

        print(
            " # 在多层索引中，指定层次标签值进行数据选取\n"
            " >>> df\n"
            f"{df}\n"
            " # 指定标签值进行检索\n"
            " >>> df.xs((1, 't3'))\n"
            f"{df.xs((1, 't3'))}\n"
            " # 跨层次指定标签值进行检索\n"
            " >>> df.xs(key=[2, 'math'], level=[0, 2])\n"
            f"{df.xs(key=[2, 'math'], level=[0, 2])}\n"

            f"{'-' * 80}\n"
            " # 指定列标签值进行检索\n"
            " >>> df1\n"
            f"{df1}\n"
            f" # 不保留level所指定的索引层的标签"
            " >>> df1.xs(key=['science'], level=0, axis=1)\n"
            f"{df1.xs(key=['science'], level=0, axis=1)}\n"

            f"{'-' * 80}\n"
            " # 保留level所指定的索引层的标签\n"
            " >>> df1.xs(key=['science'], level=0, axis=1, drop_level=False)\n"
            f"{df1.xs(key=['science'], level=0, axis=1, drop_level=False)}"
        )

        return

    def data_get(self):
        """
        get(self, key, default=None)
            Get item from object for given key (ex: DataFrame column).

            Returns default value if not found.

            Parameters
            ----------
            key : object

            Returns
            -------
            value : same type as items contained in object
        """

        data = np.random.randint(1, 9, (5, 3))
        df = pd.DataFrame(data=data, columns=list('ABC'))
        print(
            " >>> df\n"
            f"{df}\n"
            
            " >>> df.get('B')\n"
            f"{df.get('B')}\n"

            " >>> df.get('D', ValueError)\n"
            f"{df.get('D', ValueError)}\n"

            " >>> df.get(['C', 'A'], ValueError)\n"
            f"{df.get(['C', 'A'], ValueError)}"
        )

        return

    def data_take(self):
        """
        take(self: 'FrameOrSeries', indices, axis=0, is_copy: 'Optional[bool_t]' = None, **kwargs)
            -> 'FrameOrSeries'

            Return the elements in the given *positional* indices along an axis.

            This means that we are not indexing according to actual values in
            the index attribute of the object. We are indexing according to the
            actual position of the element in the object.

            Parameters
            ----------
            indices : array-like
                An array of ints indicating which positions to take.
            axis : {0 or 'index', 1 or 'columns', None}, default 0
                The axis on which to select elements. ``0`` means that we are
                selecting rows, ``1`` means that we are selecting columns.
            is_copy : bool
                Before pandas 1.0, ``is_copy=False`` can be specified to ensure
                that the return value is an actual copy. Starting with pandas 1.0,
                ``take`` always returns a copy, and the keyword is therefore
                deprecated.

                .. deprecated:: 1.0.0
            **kwargs
                For compatibility with :meth:`numpy.take`. Has no effect on the
                output.

            Returns
            -------
            taken : same type as caller
                An array-like containing the elements taken from the object.

            See Also
            --------
            DataFrame.loc : Select a subset of a DataFrame by labels.
            DataFrame.iloc : Select a subset of a DataFrame by positions.
            numpy.take : Take elements from an array along an axis.

            Examples
            --------
            >>> df = pd.DataFrame([('falcon', 'bird', 389.0),
            ...                    ('parrot', 'bird', 24.0),
            ...                    ('lion', 'mammal', 80.5),
            ...                    ('monkey', 'mammal', np.nan)],
            ...                   columns=['name', 'class', 'max_speed'],
            ...                   index=[0, 2, 3, 1])
            >>> df
                 name   class  max_speed
            0  falcon    bird      389.0
            2  parrot    bird       24.0
            3    lion  mammal       80.5
            1  monkey  mammal        NaN

            Take elements at positions 0 and 3 along the axis 0 (default).

            Note how the actual indices selected (0 and 1) do not correspond to
            our selected indices 0 and 3. That's because we are selecting the 0th
            and 3rd rows, not rows whose indices equal 0 and 3.

            >>> df.take([0, 3])
                 name   class  max_speed
            0  falcon    bird      389.0
            1  monkey  mammal        NaN

            Take elements at indices 1 and 2 along the axis 1 (column selection).

            >>> df.take([1, 2], axis=1)
                class  max_speed
            0    bird      389.0
            2    bird       24.0
            3  mammal       80.5
            1  mammal        NaN

            We may take elements using negative integers for positive indices,
            starting from the end of the object, just like with Python lists.

             >>> df.take([-1, -2])
                 name   class  max_speed
            1  monkey  mammal        NaN
            3    lion  mammal       80.5
        """

        df = self.df_list
        print(
            f" >>> df\n"
            f"{df}\n"

            f" # 按照位置选取行数据\n"
            f" >>> df.take([1, 0])\n"
            f"{df.take([1, 0])}\n"

            f" # 按照位置选取列数据\n"
            f" >>> df.take([2, 0], axis=1)\n"
            f"{df.take([2, 0], axis=1)}\n"

            f" # 按照位置选取行、列数据\n"
            f" >>> df.take([2, 0], axis=1).take([1, 0], axis=0)\n"
            f"{df.take([2, 0], axis=1).take([1, 0], axis=0)}"
            )

        return
